package dominioProblema;

import interfaceGrafica.InterfaceGrafica;
import interfaceGrafica.Mensagens;

import java.text.ParseException;
import java.util.LinkedList;

import netGames.NetGamesNRT;
import br.ufsc.inf.leobr.cliente.Jogada;
import br.ufsc.inf.leobr.cliente.exception.NaoJogandoException;

public class Mesa {

	protected Placar placar;
	protected Mao maoJog;
	protected Mao maoOp;
	protected Jogador jogador;
	protected Jogador oponente;
	protected LinkedList<Pedra> disposPedras;
	protected LinkedList<Pedra> ptaC;
	protected LinkedList<Pedra> ptaD;
	protected String vencedor;
	protected Jogador jogadorDaVez;
	protected boolean jogoEmAndamento;
	protected Armazem armazem;
	protected InterfaceGrafica iG;
	protected ControleJogada controleJogada;
	protected boolean recebeu;
	protected boolean encerra;
	protected boolean bateu;
	protected boolean passou;	
	protected NetGamesNRT ng;
	protected int pontuou;
	protected boolean dobleCincoJogado;
	protected Mensagens msg;
	protected boolean passouUltima;

	protected boolean inicializouPecas;
	protected boolean temDouble5;
	protected boolean primeiraJogada;

	public Mesa() {
		this.placar = new Placar();
		this.jogador = new Jogador();
		this.oponente = new Jogador();
		this.disposPedras = new LinkedList<Pedra>();
		this.disposPedras.clear();
		this.ptaC = new LinkedList<Pedra>();
		this.ptaD = new LinkedList<Pedra>();
		this.vencedor = null;
		this.jogadorDaVez = null;
		this.jogoEmAndamento = false;	
		this.iG = new InterfaceGrafica(this);
		this.controleJogada = new ControleJogada();
		this.recebeu = false;
		this.encerra = false;
		this.bateu = false;	
		this.ng = new NetGamesNRT(this);
		this.dobleCincoJogado = false;
		this.msg = new Mensagens();
		this.passouUltima = false;
		this.inicializouPecas = false;
		this.temDouble5 = false;
		this.primeiraJogada = false;
	}

	public void mostrarIG(boolean b) {
		this.iG.setVisible(b);
	}

	public void solicitaConexao() {
		msg.solicitaConexao();
	}

	public void sair(){
		System.exit(0);
	}

	public void zeraDados() {
		this.oponente.setNome(ng.obterNomeOponente());
		this.placar.iniciaPlacar(this.oponente.getNome(), this.jogador.getNome());
		this.maoJog = null;
		this.maoOp = null;
		this.disposPedras.clear();
		this.ptaC.clear();
		this.ptaD.clear();
	}

	public void sorteiaPedras() {
		Pedra[] sortJog = this.armazem.sorteiaPedras();
		this.maoJog = new Mao(sortJog, this.jogador.getNome());
		Pedra[] sortOp = this.armazem.sorteiaPedras();
		this.maoOp = new Mao(sortOp, this.oponente.getNome());
	}

	public Jogador verificaPrimeiro() {
		Jogador jogadorDaVez = null;
		int i = 0;	
		int k = 0;
		boolean primeiro = false;
		while ((i<5)&&(!primeiro)){
			if ((this.maoJog.getPedras()[i].getLadoA()==5)
					&&(this.maoJog.getPedras()[i].getLadoB()==5)){
				jogadorDaVez = this.jogador;
				primeiro = true;
				this.dobleCincoJogado = true;
				this.temDouble5 = true;
			}			
			i++;			
		}
		while ((k<5)&&(!primeiro)){
			if ((this.maoOp.getPedras()[k].getLadoA()==5)
					&&(this.maoOp.getPedras()[k].getLadoB()==5)){
				jogadorDaVez = this.oponente;
				primeiro = true;
				this.dobleCincoJogado = true;
			}
			k++;
		}
		if(jogadorDaVez==null){
			jogadorDaVez = this.jogador; 
		}
		return jogadorDaVez;
	}

	public void enviarJogada(Lancamento jogada) {
		this.iG.habilitarInterface(false);
		try {			
			this.ng.enviarJogada(jogada);
		} catch (NaoJogandoException e) {
			this.msg.informaErroConexao();
			e.printStackTrace();
		}
	}

	public void iniciarNovoJogo() {
		this.jogoEmAndamento = true;
		boolean conectado = ng.isConectado();
		if(!conectado){
			this.msg.solicitaConexao();
		} else {
			this.zeraDados();
			this.armazem = new Armazem();
			this.sorteiaPedras();
			this.iG.carregarPecas(maoJog);
			this.inicializouPecas = true;
			this.jogadorDaVez = this.verificaPrimeiro();
			String n = this.jogadorDaVez.getNome();
			this.msg.informaPrimeiro(n);
			if(this.jogadorDaVez==this.jogador){
				this.primeiraJogada = true;
				this.fazerJogada();
			} else {
				boolean passou = true;
				Lancamento l = new Lancamento(passou, n, this.maoJog, this.maoOp);
				boolean d5 = true;
				l.setIniciarDouble5(d5);
				l.setArmazem(this.armazem);
				l.setDisposPedras(this.disposPedras);
				l.setPtaC(this.ptaC);
				l.setPtaD(this.ptaD);
				this.enviarJogada(l);
			}
		}
	}

	public void terminarJogo() {
		this.jogador.setPontos(0);
		this.oponente.setPontos(0);
		this.limpaDadosRodada();
		this.zeraDados();
		this.msg.informaJogoAtualEncerrado();
	}

	public void fazerJogada() {	
		String n = this.jogadorDaVez.getNome();
		this.msg.informaVez(n);
		Pedra pedra = new Pedra();
		this.controleJogada.setDobleCincoJogado(dobleCincoJogado);
		this.controleJogada.atualizaDisposicao(disposPedras, ptaC, ptaD);
		boolean compativel = this.controleJogada.maoCompativel(maoJog);
		int saldo = this.armazem.getQuantPedras();
		int qtdPedras = 0;
		if(!compativel){
			while(saldo>0&&!compativel){
				pedra = this.armazem.vendePedra();
				saldo--;
				qtdPedras++;
				this.maoJog.incluiPedra(pedra);
				this.iG.incluiPedra(pedra);
				this.iG.atualizarPlacarInterface(this.jogador.getPontos(), this.oponente.getPontos(),
						this.maoOp.getSaldo(), this.armazem.getQuantPedras());
				compativel = this.controleJogada.maoCompativel(maoJog);
			}
			this.msg.informaPedraComprada(qtdPedras);
			if(saldo==0){
				this.passou = true;				
				this.msg.informaPassa(this.jogadorDaVez.getNome());
				this.passouUltima = true;
				Lancamento l = new Lancamento(this.passou, this.jogadorDaVez.getNome(), this.maoJog, this.maoOp);
				this.tratarJogada(l);
			}
		} else {
			if(this.temDouble5) {
				this.dobleCincoJogado = true;
				int i = 0;
				while (i<this.maoJog.getPedras().length){
					if(this.maoJog.getPedras()[i]!=null){
						if(this.maoJog.getPedras()[i].getPeca().equals("55")){
							pedra = this.maoJog.getPedras()[i];
							i = this.maoJog.getPedras().length; 
						}
						i++;
					}
				}
				this.temDouble5 = false;
				this.iG.iniciarDouble5(pedra);
			}
		}
	}

	public void continuarJogada(Pedra pedra, int ponta) {	
		boolean valida = false;
		valida = this.controleJogada.ehValida(pedra, ponta);
		if(!valida){
			this.msg.informaJogadaInvalida();
			this.iG.reverterAreaJogo(pedra);
		} else {
			continuarJogadaValida(pedra, ponta);
		}
	}

	private void continuarJogadaValida(Pedra pedra, int ponta) {
		this.passou = false;
		this.maoJog.removePedra(pedra);
		this.maoJog.setSaldo(this.maoJog.getSaldo() - 1);
		pedra.setClipA(this.controleJogada.verificarClipA(pedra, ponta));
		this.primeiraJogada = false;
		if ((ponta==1)||(ponta==2)){
			if(this.disposPedras.isEmpty()){
				pedra.setClipB(true);
				this.disposPedras.addFirst(pedra);
			}else{
				if(ponta==1){
					this.disposPedras.addFirst(pedra);
				}
				else{
					if(ponta==2){
						this.disposPedras.addLast(pedra);
					}
				}
			}
			if(pedra.getPeca().equals("55")){
				this.dobleCincoJogado = true;
				this.ptaC.addFirst(pedra);
				this.ptaD.addFirst(pedra);
			}
		}
		if(ponta==3){
			this.ptaC.addLast(pedra);
		}
		if(ponta==4){
			this.ptaD.addLast(pedra);
		}
		this.controleJogada.atualizaDisposicao(disposPedras, ptaC, ptaD);
		this.pontuou = this.controleJogada.verificarPontos();
		int pontos = this.jogador.getPontos() + this.pontuou;
		this.jogador.setPontos(pontos);
		this.iG.atualizarPlacarInterface(this.jogador.getPontos(), this.oponente.getPontos(),
				this.maoOp.getSaldo(), this.armazem.getQuantPedras());
		
		if(this.maoJog.getSaldo()==0) {
			this.bateu = true;
			this.oponente.setPontos(verificarPontosOp());
		}
		Lancamento l = this.criaJogada(ponta);
		this.tratarJogada(l);
	}

	private int verificarPontosOp() {
		int pontosOp = this.oponente.getPontos();
		int somaPedrasOp = 0;
		int i = 0;
		while (i<23){
			if(maoOp.getPedras()[i]!=null) {
				somaPedrasOp = somaPedrasOp + maoOp.getPedras()[i].getValor();
			}
			i++;
		}
		pontosOp = pontosOp - somaPedrasOp;
		if(pontosOp<0)
			pontosOp = 0;
		return pontosOp;
	}

	public boolean isJogoEmAndamento() {
		return jogoEmAndamento;
	}

	protected void tratarJogada(Lancamento l) {
		if(l.isPassou()){
			if(l.isRecebida()){
				if(l.getReinicio()) {
					this.jogoEmAndamento = false;
					this.reiniciarJogo();
				} else {
					if(this.passouUltima){
						this.msg.informaTrancado();
						if(!l.isJogoTrancado()) {
							l.setJogoTrancado(true);
							this.limpaDadosRodada();
							this.enviarJogada(l);
						} else {
							this.fimDeRodada();
						}
					} else {
						this.atualizaDados(l);
						this.msg.informaPassa(this.oponente.getNome());
						this.fazerJogada();
					}
				}
			}else{
				this.enviarJogada(l);
			}
		}else{
			if(l.getPontuou()!=0){
				this.msg.informaPontuacao(l.getNomeJog(), l.getPontuou());
			}
			if(!l.isBateu()){
				if(l.isRecebida()){
					this.atualizaDados(l);
					this.fazerJogada();
				}else{
					this.enviarJogada(l);
				}
			}else{
				this.msg.informaFimRodada();
				if(!l.isVitoria()){
					if(l.isRecebida()){
						this.atualizaDados(l);
						this.fimDeRodada();
					}else{
						this.limpaDadosRodada();
						this.enviarJogada(l);
					}
				}else{
					if(l.isRecebida()){
						this.atualizaDados(l);
						this.msg.informaVencedor(this.vencedor);
						int res = this.msg.confirmaEncerramento();
						if (res==1){
							this.encerra = true;
							this.terminarJogo();
						}else{
							this.reiniciarJogo();
						}
					}else{
						this.msg.informaVencedor(this.vencedor);
						this.limpaDadosRodada();
						this.enviarJogada(l);
					}
				}
			}
		}
	}

	public Lancamento criaJogada(int ponta) {
		Lancamento j = new Lancamento();
		j.setRecebida(false);
		j.setPassou(this.passou);
		j.setBateu(this.bateu);
		j.setPontuou(this.pontuou);
		j.setVitoria(this.temVencedor());
		j.setSaldoPedras(this.maoJog.getSaldo());
		j.setNomeJog(this.jogadorDaVez.getNome());
		j.setPonta(ponta);
		j.setArmazem(this.armazem);
		j.setPontJog(this.jogador.getPontos());
		j.setMaoJog(this.maoJog);
		j.setMaoOp(this.maoOp);
		j.setDobleCincoJogado(dobleCincoJogado);
		j.setDisposPedras(disposPedras);
		j.setPtaC(ptaC);
		j.setPtaD(ptaD);
		j.setVencedor(vencedor);
		j.setPontOp(this.oponente.getPontos());
		return j;
	}

	public void atualizaDados(Lancamento l) {
		this.recebeu = l.isRecebida();
		this.bateu = l.isBateu();
		this.pontuou = l.getPontuou();
		this.maoOp = l.getMaoJog();
		this.maoJog = l.getMaoOp();
		this.armazem = l.getArmazem();
		this.placar.atualizaPlacar(l.getSaldoPedras(), l.getPontJog(), this.armazem.getQuantPedras());
		this.disposPedras = l.getDisposPedras();
		this.ptaC = l.getPtaC();
		this.ptaD = l.getPtaD();
		this.dobleCincoJogado = l.isDobleCincoJogado();
		this.vencedor = l.getVencedor();
		this.jogador.setPontos(l.getPontOp());
		this.oponente.setPontos(l.getPontJog());
		this.iG.atualizarPlacarInterface(this.jogador.getPontos(), this.oponente.getPontos(),
				l.getSaldoPedras(), this.armazem.getQuantPedras());
		this.iG.repaint();
	}

	private boolean temVencedor() {
		int pontuacaoMaxima = 100;
		boolean venc = false;
		int pontosJog = this.jogador.getPontos();
		int pontosOp = this.oponente.getPontos();
		if((pontosJog>=pontuacaoMaxima)||(pontosOp>=pontuacaoMaxima)) {
			venc = true;
			if(pontosJog>pontosOp) {
				this.vencedor = this.jogador.getNome();
			} else {
				this.vencedor = this.oponente.getNome();
			}
		} else {
			venc = false;
		}
		return venc;
	}

	public void fimDeRodada() {
		this.armazem = new Armazem();
		this.limpaDadosRodada();
		this.sorteiaPedras();
		this.iG.carregarPecas(maoJog);
		this.inicializouPecas = true;
		this.jogadorDaVez = this.verificaPrimeiro();
		String n = this.jogadorDaVez.getNome();
		this.msg.informaPrimeiro(n);
		if(this.jogadorDaVez==this.jogador){
			this.fazerJogada();
		}else{
			boolean passou = true;
			Lancamento l = new Lancamento(passou, n, this.maoJog, this.maoOp);
			l.setIniciarDouble5(true);
			l.setArmazem(this.armazem);
			l.setDisposPedras(disposPedras);
			l.setPtaC(ptaC);
			l.setPtaD(ptaD);
			this.enviarJogada(l);
		}		
	}

	public void reiniciarJogo() {		
		boolean andamento = this.isJogoEmAndamento();
		this.terminarJogo();
		if (andamento){
			Lancamento l = this.criaReinicio();
			this.enviarJogada(l);
		} else {
			this.iniciarNovoJogo();
		}
	}

	private Lancamento criaReinicio() {
		Lancamento j = new Lancamento();
		j.setReinicio(true);
		j.setPassou(true);
		return j;
	}

	public void limpaDadosRodada() {
		this.disposPedras.clear();
		this.ptaC.clear();
		this.ptaD.clear();
		this.iG.reinicializar();
		this.dobleCincoJogado = false;
		this.controleJogada.limpaDadosRodada();
		this.inicializouPecas = false;
		this.iG.atualizarPlacarInterface(this.jogador.getPontos(), this.oponente.getPontos(), 0, 28);
		this.bateu = false;
	}

	public void recebeJogada(Jogada jogada) {
		this.iG.habilitarInterface(true);
		Lancamento l = (Lancamento) jogada;
		l.setRecebida(true);
		this.jogadorDaVez = this.jogador;
		if(!inicializouPecas){
			this.oponente.setNome(ng.obterNomeOponente());
			this.jogoEmAndamento = true;
			this.primeiraJogada = true;
			this.maoOp = l.getMaoJog();
			this.maoJog = l.getMaoOp();
			this.iG.carregarPecas(maoJog);	
			if(l.isIniciarDouble5()) {
				this.temDouble5 = true;
			} else {
				this.iG.atualizarAreaJogo(l.getDisposPedras(), l.getPtaC(), l.getPtaD(), l.getPonta());
			}
			this.inicializouPecas = true; 
		} else {
			if(!l.isBateu()){
				if(!l.passou){
					this.iG.atualizarAreaJogo(l.getDisposPedras(), l.getPtaC(), l.getPtaD(), l.getPonta());
				} else {
					if(l.isJogoTrancado()) {
						this.passouUltima = true;
					}
				}
			}
		}
		this.tratarJogada(l);
	}

	public boolean desconectarNetGames() {
		boolean conectado = ng.isConectado();
		if(conectado){
			conectado = ng.desconectarNetGames();
		}
		this.msg.informaDesconexaoOk();
		return conectado;
	}

	public void iniciarPartidaRede(boolean vez) {
		if(vez){
			this.iniciarNovoJogo();			
		}else{
			this.msg.informaAguardarOponente();
		}
	}

	public boolean conectarNetGames(String n, String s) {		
		boolean conectado = ng.isConectado();		
		if (!conectado){
			conectado = ng.conectarNetGames(n, s);
			if (!conectado){
				this.msg.informaErroConexao();
			}
		}
		this.jogador.setNome(n);
		this.msg.informaConexaoOk();
		return conectado;
	}

	public void iniciarPartida() {
		this.ng.iniciarPartidaRede();		
	}

	public static void main(String[] args) throws ParseException {
		Mesa me = new Mesa();
		try {			
			me.mostrarIG(true);			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}